package io.renren.common.base;

import com.alibaba.fastjson.JSON;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author liangpei
 * @version 1.0
 * @description: okHttp3的连接配置
 * @date 2024/3/15 10:32
 */
@Component
public class OkHttpClientBuilder {
    private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpClientBuilder.class);

    /**
     * 同步阻塞等待执行结果的时间，单位毫秒
     */
    private static Integer DEFAULT_WAIT_TIMEOUT = 60000;

    private static OkHttpClient okHttpClient;
    // 为使用静态调用异步注入
    @Autowired
    private OkHttpClient getOkHttpClient;
    @PostConstruct
    public void init() {
        System.out.println("初始化okhttp");
        okHttpClient = getOkHttpClient;
    }

    private OkHttpClientBuilder() {}


    static {
        // 向JVM注册一个关闭钩子，当服务准备停止时，等待 OkHttpClient 中任务执行完毕再停止，防止线程池中正在执行的任务突然中断
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                final Logger logger = LoggerFactory.getLogger(OkHttpClient.class);
                int count = 100;
                Dispatcher dispatcher = okHttpClient.dispatcher();
                logger.info("ShutdownHook start：queuedCallsCount {} , runningCallsCount {}", dispatcher.queuedCallsCount(), dispatcher.runningCallsCount());
                while (dispatcher.queuedCallsCount() > 0 || dispatcher.runningCallsCount() > 0) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        logger.error("ShutdownHook interrupted：queuedCallsCount {} , runningCallsCount {}", dispatcher.queuedCallsCount(), dispatcher.runningCallsCount());
                        break;
                    }
                    // 防止无限循环
                    if (--count == 0) {
                        LOGGER.error("ShutdownHook timeout：queuedCallsCount {} , runningCallsCount {}", dispatcher.queuedCallsCount(), dispatcher.runningCallsCount());
                        break;
                    }
                }
                logger.info("ShutdownHook end：queuedCallsCount {} , runningCallsCount {}", dispatcher.queuedCallsCount(), dispatcher.runningCallsCount());
            }
        }));
    }


    /**
     * 同步执行请求，公共方法
     * @param request
     * @return
     */
    public static OkHttpClientResult syncRequest(Request request){
        try (Response response = okHttpClient.newCall(request).execute()){
            return buildResponseResult(request, response);
        } catch (Exception e) {
            LOGGER.error("request error，request:" +  request, e);
            return new OkHttpClientResult(false, 500, "request error");
        }
    }



    /**
     * 异步执行请求，同步阻塞编程等待返回结果
     * 此方式在多线程环境下请求处理依然能保持高性能，根据不同的场景显式对ConnectionPool进行调优处理
     * @param request
     * @return
     */
    public static OkHttpClientResult syncResponse(Request request) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("request start，request:{}", request);
        }

        int retryCount = 0;
        final int MAX_RETRIES = 3;

        while (retryCount < MAX_RETRIES) {
            retryCount++;

            Call call = okHttpClient.newCall(request);
            CompletableFuture<Response> completableFuture = new CompletableFuture<>();

            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    completableFuture.completeExceptionally(e);
                }

                @Override
                public void onResponse(Call call, Response response) {
                    try {
                        if (!response.isSuccessful()) {
                            completableFuture.completeExceptionally(new IOException("Non-successful HTTP response: " + response));
                        } else {
                            // 先完成 CompletableFuture，再关闭响应体
                            completableFuture.complete(response);
                        }
                    } catch (Exception e) {
                        completableFuture.completeExceptionally(e);
                    }
                }
            });

            try {
                Response response = completableFuture.get(DEFAULT_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);

                try {
                    OkHttpClientResult result = buildResponseResult(request, response);
                    LOGGER.debug("========== " + JSON.toJSONString(response));
                    return result;
                } catch (IOException e) {
                    Throwable cause = e.getCause();

                    if (cause instanceof IOException) {
                        if (retryCount < MAX_RETRIES) {
                            LOGGER.warn("Request error in buildResponseResult, retrying... (Attempt " + retryCount + ")");
                        } else {
                            LOGGER.error("Request error after " + MAX_RETRIES + " attempts, request: " + request, cause);
                            return new OkHttpClientResult(false, 500, "request error");
                        }
                    } else {
                        LOGGER.error("Unexpected error in buildResponseResult, request: " + request, cause);
                        Thread.currentThread().interrupt(); // 恢复中断状态
                        throw new RuntimeException("An unexpected error occurred during request execution", cause);
                    }
                }
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                Throwable cause = e.getCause();

                if (cause instanceof IOException || cause instanceof TimeoutException) {
                    if (retryCount < MAX_RETRIES) {
                        LOGGER.warn("Request error, retrying... (Attempt " + retryCount + ")");
                    } else {
                        LOGGER.error("Request error after " + MAX_RETRIES + " attempts, request: " + request, cause);
                        return new OkHttpClientResult(false, 500, "request error");
                    }
                } else {
                    LOGGER.error("Unexpected error, request: " + request, cause);
                    Thread.currentThread().interrupt(); // 恢复中断状态
                    throw new RuntimeException("An unexpected error occurred during request execution", cause);
                }
            }
        }

        LOGGER.error("All retries failed, request: " + request);
        return new OkHttpClientResult(false, 500, "all retries failed");
    }




    /**
     * 封装返回值
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    private static OkHttpClientResult buildResponseResult(Request request, Response response) throws IOException {
        try {
            if(LOGGER.isDebugEnabled()){
                LOGGER.debug("request end，request:{}, response:{}", request, response);
            }
            ResponseBody responseBody = response.body();
            OkHttpClientResult result = new OkHttpClientResult();
            result.setSuccess(response.isSuccessful());
            result.setCode(response.code());
            result.setMessage(response.message());
            result.setHeaders(response.headers().toMultimap());
            if(Objects.nonNull(responseBody)){
                result.setBody(responseBody.bytes());
            }
            if(!result.isSuccess()){
                LOGGER.warn("request fail, request:{}, response:{}", request, response);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            // 确保关闭响应体
            response.body().close();
        }
    }



}
